SQL Werken met samengestelde logische operatoren
Doelstelling
Na deze les ben je in staat om rijen uit een tabel te selecteren met behulp van logische expressies, namelijk samengestelde logische operatoren.
Praktijk
Een eenvoudig voorbeeld moet dat duidelijk maken:
use JefInghelbrecht; select Familienaam, Titel from Boeken where Familienaam = 'Aveni' or Familienaam = 'Hawking';
Met als resultaat de boeken van Aveni en van Hawking:
use JefInghelbrecht; select Familienaam, Titel from Boeken where Familienaam = 'Aveni' or Familienaam = 'Lévi Strauss';
Tik je een auteur in die niet in de tabel aanwezig is krijg je de boeken van slechts één auteur, het gaat hier immers om een of operator:
And en Or combineren
Je wil alle wiskunde boeken van Aveni en Hawkins. Welke expressie moet je hiervoor gebruiken?
Hoe zet je die vraag om in logische taal?
Alle wiskunde boeken dat wil zeggen alle boeken waarvan in de kolom categorie de waarde wiskunde staat:
Categorie = 'Wiskunde'.
Alle boeken van Aveni dat schrijf je als:
Familienaam = 'Aveni'.
Alle boeken van De Roover, dat schrijf je als:
Familienaam ='De Roover'.
Dus alle wiskunde boeken van Aveni en van De Roover zou je kunnen schrijven als:
use JefInghelbrecht; select Familienaam, Titel from Boeken where Categorie = 'Wiskunde' and Familienaam = 'Aveni' or Familienaam = 'De Roover';
Dat Aveni niet geselecteerd werd is logisch, de man heeft geen wiskunde boeken geschreven. Maar dat De Roover werd geselecteerd is niet wat we wilden. Die mens schrijft alleen geschiedenisboeken over het geldwezen.
Dit komt omdat we de volgorde van de operatoren niet goed hebben toegepast. De And heeft voorrang op de Of. D.w.z. dat de And eerst wordt geëvalueerd. Er wordt dus eerst gekeken naar het eerste deel van de samengestelde expressie:
Categorie = 'Wiskunde' and Familienaam = 'Aveni'
En die is False omdat Aveni geen wiskunde boeken schrijft. En dan wordt het tweede deel geëvalueerd:
or Familienaam = 'De Roover'
Hier wordt alleen gekeken naar de familienaam en niet naar de categorie. Dus worden alle boeken van De Roover geselecteerd.
use JefInghelbrecht; select Familienaam, Titel from Boeken where Categorie = 'Wiskunde' and Familienaam = 'Aveni' or Categorie = 'Wiskunde' and Familienaam = 'Hawking';
Nu hebben we een juiste logische expressie die we straks nog kunnen vereenvoudigen. Eerst een oefening. Hoe komt het dat de wiskundeboeken van Hawking niet geselecteerd worden alhoewel er ten minste één wiskundeboek van hem in de tabel zit?
Als je ronde haakjes gebruikt om logische expressies te gebruiken kan je de expressies vereenvoudigen en verduidelijken. Met ronde haakjes is de expressie leesbaarder en is het risico op foute interpretaties veel kleiner:
use JefInghelbrecht select Familienaam, Titel from Boeken where Categorie = 'Wiskunde' and (Familienaam = 'Aveni' or Familienaam = 'Hawking');
Nieuwe voorbeelden
use ModernWays; -- ik wil er wel een van Bloch lezen maar dan moet -- het filosofie zijn voor de rest maakt het me niet uit select Voornaam, Familienaam, Titel from Boeken where (categorie = 'Filosofie' and Familienaam = 'Bloch') or (not Familienaam = 'Bloch')
Selecteer alle boeken geschreven door Jan Beth, of boeken die jonger zijn dan 2000:
-- ji -- 11 december 2012 -- use A88586JefInghelbrecht; -- alle boeken geschreven door Jan Beth, of boeken die jonger zijn dat 2000 select * from Boeken where Voornaam = 'Jan' and Familienaam = 'Beth' or Verschijningsdatum < '2000';
Het is beter om altijd de ronde haakjes te gebruiken om de problemen met prioriteit te vermijden:
select * from Boeken where (Voornaam = 'Jan' and Familienaam = 'Beth') or (Verschijningsdatum < '2000')
Selecteer alle boeken die door Jan geschreven zijn en die geschreven zijn door beth of jonger dan 2000
eerste voorwaarde: alle boeken die door Jan geschreven zijn:
Voornaam = 'Jan'
tweede voorwaarde: die boeken zijn geschreven door Beth of zijn jonger dan 2000:
Familienaam = 'Beth' or Verschijningsdatum < '2000'
We voegen de eerste en de twee voorwaarde samen:
select * from Boeken where Voornaam = 'Jan' and (Familienaam = 'Beth' or Verschijningsjaar < '2000')
insert into Boeken (Voornaam, Familienaam, Titel, Verschijningsjaar, Categorie, InsertedBy) values ('Jan', 'De Wilde', 'De fanfare van dorst', '1990', 'Liedjestekst', 'JI');
Zal Jan De Wilde met onderstaande SELECT in de lijst worden opgenomen?
select * from Boeken where Voornaam = 'Jan' and (Familienaam = 'Beth' or Verschijningsjaar < '2000')
Het antwoord is ja. Want het criterium is boeken geschreven door Jan en boeken geschreven door Beth of jonger dan 2000.
Oefeningen
- Bewaar de oefeningen in LogischeExpressiesOefeningen.sql;
- Selecteer de boeken van twee verschillende auteurs (de namen kies jezelf);
- Selecteer alle boeken die verschillen van één bepaalde auteur, m.a.w. alle boeken behalve van één auteur (de naam kies jezelf);
- Insert Hugo Claus, De verwondering, Antwerpen, Manteau, 1970;
- Insert Hugo Raes, Jagen en gejaagd worden, Antwerpen, De Bezige Bij, 1954;
- Insert Jean-Paul Sarthe, Het zijn en het niets, 1943, Parijs, Gallimard;
- Selecteer alle boeken van de auteurs die de voornaam Hugo of Jean-Paul hebben;
- Selecteer alle boeken van de auteurs die de voornaam Hugo of Jean-Paul hebben en een boek in 1970 hebben geschreven;
- Je hebt de familienaam Sarthe verkeerd geschreven het moet Sartre zijn, schrijf een update statement die die familienaam verbetert;
- Voeg de categorie 'Literatuur' toe voor de boeken van Hugo Claus en Hugo Raes.
- Voor het boek van Jean-Paul Sartre met de titel Het zijn en het niets voeg je de categorie 'Filosofie' toe.
- Selecteer de boeken van Sartre met de categorie Filosofie en de boeken geschreven door Hugo Claus.
Kenny merkte op dat er een SQL variant bestaat om vraag 2 op te lossen zonder gebruik te maken van logische operator <>:
--- Alle auteurs buiten auteur met familienaam Beth select * from Boeken except select * from Boeken where Familienaam = 'Beth';